package ontology;

import gui.Map;
import jade.core.AID;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.StringTokenizer;

import agents.UtilsAgents;

/**
 * <p>
 * <B>Title:</b> Fire Evacuation
 * </p>
 * 
 * <p>
 * Information about the current game. This object is initialized from a file.
 * <p>
 * 
 * @author Carolina Arce & Caterina Bruno
 * @see ontology.AuxInfo
 */

public class InfoGame implements java.io.Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private AuxInfo info;
	public static List<AID> removedAgents;
	private Map map1;
	public int nrows;
	public int ncols;
	public int nfloors;
	private List<Cell> c_injured;
	private int numCelFree;
	private List<Cell> panicCivilian;
	private UtilsAgents utils;
	private int numOstacle = 0;
	public int[] diedPerFloor;

	static private boolean DEBUG = false;

	public InfoGame() {
		info = new AuxInfo();
		c_injured = new ArrayList<Cell>();
		setNumCelFree(0);
		this.map1 = null;
		removedAgents = new ArrayList<AID>();
		panicCivilian = new ArrayList<Cell>();
		diedPerFloor = new int[2];
	}

	public AuxInfo getInfo() {
		return info;
	}

	public void setInfo(AuxInfo info) {
		this.info = info;
	}

	// public Cell[][] getMap() { return this.map; }

	/*
	 * public Cell getCell(int x, int y) { return this.map[x][y]; } public void
	 * setCell(int x, int y, Cell c) { this.map[x][y] = c; }
	 */

	public int getNrows() {
		return nrows;
	}

	public void setNrows(int nrows) {
		this.nrows = nrows;
	}

	public int getNcols() {
		return ncols;
	}

	public void setNcols(int ncols) {
		this.ncols = ncols;
	}

	public Map getMap() {
		// return this.map1;
		return this.map1;
	}

	/**
	 * 
	 * @param x
	 *            row
	 * @param y
	 *            col
	 * @param l
	 *            floor
	 * @return Cell
	 */
	public Cell getCell(int row, int col, int floor) {
		// return this.map1[l][x][y];
		return this.map1.getCell(row, col, floor);
	}

	public void setCell(int row, int col, Cell c, int floor) {
		// this.map1[l][x][y] = c;
		this.map1.setCell(row, col, floor, c);
	}

	private void showMessage(String s) {
		if (this.DEBUG)
			System.out.println(s);
	}

	// /**
	// * We write the string specified into a file.
	// * @param content String to write
	// * @param file Pathname of the file
	// * @return Nothing
	// */
	// private void writeFile(String content, File file) throws IOException {
	// StringBuffer sb = new StringBuffer(content);
	// PrintStream outFile = new PrintStream(new FileOutputStream(file));
	// for (int i = 0; i < content.length(); i++) {
	// outFile.print(sb.charAt(i));
	// }
	// // System.out.println(content.length()+" characters write");
	// }
	public void writeGameResult(String fileOutput, Cell[][][] t)
			throws IOException, Exception {
		File file = new File(fileOutput);
		String content = "" + this.info.getTime() + "\n";
		for (int f = 0; f < this.nfloors; f++)
			for (int r = 0; r < t[0].length; r++) {
				for (int c = 0; c < t[0][0].length; c++) {
					Cell ca = t[f][r][c];
					content = content + Cell.getCellType(ca.getCellType());
					if (ca.getCellType() == Cell.FIRE)
						content = content + ca.getFireIntensityUnits();

					if (ca.getCellType() == Cell.FREE
							&& ca.isThereAnAgent() == true)
						content = content + ca.getAgent().getName();
					content += "\t";
				}
				content += "\n";
			}
		UtilsGUI.writeFile(content, file);
		showMessage("File written");
	}

	public void readGameFile(String file) throws IOException, Exception {
		FileReader fis = new FileReader(file);
		BufferedReader dis = new BufferedReader(fis);
		int NROWS = 0, NCOLS = 0, NFLOORS = 0;

		String dades = dis.readLine();
		StringTokenizer st = new StringTokenizer(dades, " ");
		this.info.setTime(Integer.parseInt(st.nextToken()));
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		// this.info.setTimeout(Long.parseLong(st.nextToken()));
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		NROWS = Integer.parseInt(st.nextToken());
		nrows = NROWS;
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		NCOLS = Integer.parseInt(st.nextToken());
		ncols = NCOLS;
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		NFLOORS = Integer.parseInt(st.nextToken());
		nfloors = NFLOORS;
		// this.map = new Cell[NROWS][NCOLS];
		// this.map1= new Cell[NFLOORS][NROWS][NCOLS];
		this.map1 = new Map(nrows, ncols, nfloors);
		/*
		 * this.map1.nfloor = nfloors; this.map1.length = nrows; this.map1.width
		 * = ncols;
		 */
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		this.info.setNumCivillians(Integer.parseInt(st.nextToken()));
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		this.info.setNumEvacuators(Integer.parseInt(st.nextToken()));
		dades = dis.readLine();
		st = new StringTokenizer(dades, " ");
		this.info.setNumFiremen(Integer.parseInt(st.nextToken()));

		for (int floor = 0; floor < nfloors; floor++) {
			int col = 0, row = 0;
			// Leggi mappa
			while (((dades = dis.readLine()) != null) && row < nrows) {

				col = 0;
				st = new StringTokenizer(dades, " ");
				while (st.hasMoreTokens()) {
					String str = st.nextToken();
					if (str.equals("_")) {
						// this.map1[floor][row][col]= new Cell(Cell.FREE);
						this.map1.setCell(row, col, floor, new Cell(Cell.FREE));
						this.setNumCelFree(this.getNumCelFree() + 1);
					} else {
						if (str.charAt(0) == 'b') {
							this.map1.setCell(row, col, floor, new Cell(
									Cell.OBJECT));
							numOstacle++;

						} else if (str.charAt(0) == 'd') {
							this.map1.setCell(row, col, floor, new Cell(
									Cell.DOOR));

						} else if (str.charAt(0) == 's') {
							this.map1.setCell(row, col, floor, new Cell(
									Cell.STAIRS));

						}

						else if (str.charAt(0) == '*') {

						}

						else {
							this.map1.setCell(row, col, floor, new Cell(
									Cell.FIRE));

							if (str.length() > 1) {
								str = str.substring(2, str.length() - 1);
								StringTokenizer st2 = new StringTokenizer(str,
										",");
								double points;
								points = Double.parseDouble(st2.nextToken());
								this.map1.getCell(row, col, floor)
										.setFireIntensityUnits(points);
								this.map1.getCell(row, col, floor)
										.setDiscovered(true);
								this.info.addFirePoints(this.map1.getCell(row,
										col, floor));
							}
						}
					}
					this.map1.getCell(row, col, floor).setRow(row);
					this.map1.getCell(row, col, floor).setColumn(col);
					col++;
				}
				row++;
			}

		}

		this.c_injured = new ArrayList<Cell>();

	}

	/*** Clase de caterina ********************/
	public List<Cell> getCenters() {
		return this.c_injured;
	}

	public void addCenters(Cell c) {
		this.c_injured.add(c);

	}

	public int getNfloors() {
		return nfloors;
	}

	public void setNfloors(int nfloors) {
		this.nfloors = nfloors;
	}

	public List<AID> getRemovedAgents() {
		return removedAgents;
	}

	public boolean isAgentRemoved(AID aid) {
		System.err.println("IS REMOVED AID= " + aid.getLocalName());
		for (int i = 0; i < removedAgents.size(); i++) {
			AID a = removedAgents.get(i);
			 System.err.println("WITH AID= " + a.getLocalName());
			if (aid.getName().equals(a.getName())) {
				 System.err.println("Agent " + aid.getLocalName() +
				 " removed. ");
				return true;
			}

		}
		return false;
	}

	public void addRemovedAgent(AID aid) {
		this.removedAgents.add(aid);
	}

	/***** Carolina **********************************/

	public List<Cell> getPanicCivilianByFloor(Cell evacuatorCell) {

		for (int x = 0; x < this.getMap().length; x++) {
			for (int y = 0; y < this.getMap().width; y++) {
				Cell c = this.getCell(x, y, evacuatorCell.getFloor());
				if (c != null)
					if (c.isThereAnAgent()) {
						InfoAgent a = c.getAgent();
						if (a.getAgentType() == InfoAgent.CIVILIAN) {
							if (a.getPanic() == 80)
								this.panicCivilian.add(c);
						}
					}
			}
		}

		/****** Sort panicCell **/
		Cell temp = null;
		Cell ev = evacuatorCell;
		int distR, distC, distT1, distT2;

		for (int i = 0; i < panicCivilian.size(); i++) {
			Cell c1 = panicCivilian.get(i);
			distR = Math.abs(c1.getRow() - ev.getRow());
			distC = Math.abs(c1.getColumn() - ev.getColumn());
			distT1 = distR + distC;

			for (int j = i + 1; j < panicCivilian.size(); j++) {
				Cell c2 = panicCivilian.get(j);
				distR = Math.abs(c2.getRow() - ev.getRow());
				distC = Math.abs(c2.getColumn() - ev.getColumn());
				distT2 = distR + distC;

				if (distT2 < distT1) {
					temp = c1;
					panicCivilian.set(i, c2);
					panicCivilian.set(j, temp);
				}

			}
		}

		return this.panicCivilian;
	}

	public void cleanMap() {
		for (int f = 0; f < this.map1.nfloor; f++) {
			for (int x = 0; x < this.map1.length; x++) {
				for (int y = 0; y < this.map1.width; y++) {
					Cell c = this.map1.getCell(x, y, f);
					if (c.isThereAnAgent()) {
						this.setCell(x, y, (new Cell(Cell.FREE)), f);
					}
				}
			}
		}

	}

	public int getCellFree() {
		// TODO Auto-generated method stub
		return 0;
	}

	public int getNumCelFree() {
		return numCelFree;
	}

	public void setNumCelFree(int numCelFree) {
		this.numCelFree = numCelFree;
	}

	public void shuffleAgents() throws Exception {
		java.util.List<InfoAgent> evacuatorsagents = new java.util.ArrayList<InfoAgent>();
		java.util.List<InfoAgent> firemansagents = new java.util.ArrayList<InfoAgent>();
		java.util.List<InfoAgent> civilansagents = new java.util.ArrayList<InfoAgent>();
		java.util.List<Cell> cellsC = new java.util.ArrayList<Cell>();
		java.util.List<Cell> cellsE = new java.util.ArrayList<Cell>();
		java.util.List<Cell> cellsF = new java.util.ArrayList<Cell>();

		Cell temp = null;
		InfoAgent curr = null;
		// System.out.println("currentGame.nfloors" + currentGame.nfloors);
		for (int f = 0; f < this.getMap().nfloor; f++) {
			for (int x = 0; x < this.getMap().length; x++)
				for (int y = 0; y < this.getMap().width; y++) {
					temp = this.getMap().getCell(x, y, f);
					if (temp.isThereAnAgent()
							&& temp.getAgent().getAgentType() == InfoAgent.CIVILIAN) {
						civilansagents.add(temp.getAgent());
						cellsC.add(temp);
					}
					if (temp.isThereAnAgent()
							&& temp.getAgent().getAgentType() == InfoAgent.EVACUATOR) {
						evacuatorsagents.add(temp.getAgent());
						cellsE.add(temp);
					}
					if (temp.isThereAnAgent()
							&& temp.getAgent().getAgentType() == InfoAgent.FIREMAN) {
						firemansagents.add(temp.getAgent());
						cellsF.add(temp);
					}
				}

		}

		Collections.shuffle(evacuatorsagents);
		Collections.shuffle(firemansagents);
		Collections.shuffle(civilansagents);
		temp = null;

		for (int i = 0; i < cellsC.size(); i++) {

			temp = cellsC.get(i);
			curr = temp.getAgent();

			// temp.removeAgent(curr);
			// temp.addAgent(agents.get(i));
			this.getMap()
					.getCell(temp.getRow(), temp.getColumn(), temp.getFloor())
					.removeAgent(curr);
			// if(temp.getAgent().getAgentType()== InfoAgent.CIVILIAN){
			temp = getFreeCell(this, temp.getFloor());
			this.getMap()
					.getCell(temp.getRow(), temp.getColumn(), temp.getFloor())
					.addAgent(civilansagents.get(i));
			// }

		}

		for (int i = 0; i < cellsE.size(); i++) {

			temp = cellsE.get(i);
			curr = temp.getAgent();

			this.getMap()
					.getCell(temp.getRow(), temp.getColumn(), temp.getFloor())
					.removeAgent(curr);

			temp = getFreeCell(this, temp.getFloor());
			this.getMap()
					.getCell(temp.getRow(), temp.getColumn(), temp.getFloor())
					.addAgent(evacuatorsagents.get(i));
			// }

		}

		for (int i = 0; i < cellsF.size(); i++) {

			temp = cellsF.get(i);
			curr = temp.getAgent();

			this.getMap()
					.getCell(temp.getRow(), temp.getColumn(), temp.getFloor())
					.removeAgent(curr);
			temp = getFreeCell(this, temp.getFloor());
			this.getMap()
					.getCell(temp.getRow(), temp.getColumn(), temp.getFloor())
					.addAgent(firemansagents.get(i));
			// }

		}

	}

	public Cell getFreeCell(InfoGame currentGame, int f) {
		int x = 0;
		int y = 0;

		Random rand = new Random();
		/* Ritorna il una cella libera per posizionare gli agenti */
		// System.out.println(rand + "rand");
		boolean found = true;

		while (found) {

			x = rand.nextInt(currentGame.getNcols());
			y = rand.nextInt(currentGame.getNrows());
			if (currentGame.getCell(x, y, f).getCellType() == Cell.FREE
					&& currentGame.getCell(x, y, f).isThereAnAgent() == false) {
				found = false;
				// System.out.println(x +"-"+ y );
			}
		}

		return currentGame.getCell(x, y, f);

	}

	public List<Cell> getCivilianInjuredPosition(Cell paramedic) {
		for (int x = 0; x < this.getMap().length; x++) {
			for (int y = 0; y < this.getMap().width; y++) {
				Cell c = this.getCell(x, y, paramedic.getFloor());
				if (c != null)
					if (c.isThereAnAgent()) {
						InfoAgent a = c.getAgent();
						if (a.getAgentType() == InfoAgent.CIVILIAN) {
							if (a.isInjured())
								this.c_injured.add(c);
						}
					}
			}
		}

		/****** Sort panicCell **/
		Cell temp = null;
		int distR, distC, distT1, distT2;

		for (int i = 0; i < c_injured.size(); i++) {
			Cell c1 = c_injured.get(i);
			distR = Math.abs(c1.getRow() - paramedic.getRow());
			distC = Math.abs(c1.getColumn() - paramedic.getColumn());
			distT1 = distR + distC;

			for (int j = i + 1; j < c_injured.size(); j++) {
				Cell c2 = c_injured.get(j);
				distR = Math.abs(c2.getRow() - paramedic.getRow());
				distC = Math.abs(c2.getColumn() - paramedic.getColumn());
				distT2 = distR + distC;

				if (distT2 < distT1) {
					temp = c1;
					c_injured.set(i, c2);
					c_injured.set(j, temp);
				}

			}
		}
		return c_injured;
	}

	public void diedAgents() {

		for (int f = 0; f < this.getMap().nfloor; f++) {
			for (int x = 0; x < this.getMap().length; x++) {
				for (int y = 0; y < this.getMap().width; y++) {

					Cell c = this.getCell(x, y, f);
					if (c != null)
						if (c.isThereAnAgent()) {
							InfoAgent a = c.getAgent();

							if (a.died)
								this.diedPerFloor[f]++;

						}
				}
			}
		}
	}


	/**************************************/

	public float getNumOstacles() {
		// TODO Auto-generated method stub
		return numOstacle;
	}

	public float countFirePoints() {
		float countF = 0;

		for (int f = 0; f < this.getMap().nfloor; f++) {
			for (int x = 0; x < this.getMap().length; x++) {
				for (int y = 0; y < this.getMap().width; y++) {
					Cell c = this.getCell(x, y, f);
					if (c.getCellType() == Cell.FIRE)
						countF++;

				}
			}
		}
		// System.out.println("countFirePoints " + countF);
		return countF;
	}

} // endof class InfoPartida
